/*
    1.对于那些有一点 JavaScript 使用经验但从未真正理解闭包概念的人来说，理解闭包可以看作是某种意义上的重生
    2.什么是作用域？
        作用域就是一套规则，用于确定在何处以及如何查找变量（标识符）的规则
    3.作用域就是查找变量的地方

    4.作用域链
        我们在查找b变量的时候，先在函数作用域中查找，没有找到，再去全局作用域中查找，有一个往外层查找的过程。我们好像是顺着一条链条从下往上查找变量，这条链条，我们就称之为作用域链。
    5.作用域嵌套
        全局作用域
         外层作用域
            当前作用域
        类似 一个洋葱圈一样，一直嵌套下去；
    6.作用域中变量（标识符）的查找规则
        javaScript 也有一定的编译的过程； var name ="dsdsd"
        编译器在当前作用域中声明一个变量name
        运行时引擎在作用域中查找该变量，找到了name变量并为其赋值
        代码
            console.log(name); // 输出undefined
            var name = 'iceman'; 
            在var name = 'iceman'的上一行输出name变量，并没有报错，输出undefined，说明输出的时候该变量已经存在了，只是没有赋值而已。
    7.两种查找类型：输出变量的值的时候的查找类型是RHS，找到变量为其赋值的查找类型是LHS。
    8.其中a=4这类赋值操作，也是会从当前作用域中查找，如果没有找到再到外层作用域中找，如果到全局变量啊这个变量，在非严格模式下会创建一个全局变量a。不过，非常不建议这么做，因为轻则污染全局变量，重则造成内存泄漏（比如：a = 一个非常大的数组，a在全局变量中，一直用有引用，程序不会自动将其销毁）
    9.词法作用域：
        所谓的词法作用域就是在你写代码时将变量和块作用域写在哪里来决定，也就是词法作用域是静态的作用域，在你书写代码时就确定了。
    10.
    注1：eval()和with可以通过其特殊性用来“欺骗”词法作用域，不过正常情况下都不建议使用，会产生性能问题。
    注2：ES6中有了let、const就有了块级作用域，后面会专门介绍。
*/

//2
function foo1() {
    var a = 'iceman';
    console.log(a); // 输出"iceman"
}
foo1();//函数内 函数作用域 //有看到函数第一行有定义a变量的代码var a = 'iceman'。
var b = 'programmer';
function foo() {
    console.log(b); // 输出"programmer"
}
foo();//函数外 全局作用域 //在输出b的时候，自己函数内部没有找到变量b，那么就在外层的全局中查找，找到了就停止查找并输出了。